package com.esayread.utils

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.util.Log
import com.esayread.data.BookFormat
import com.tom_roush.pdfbox.android.PDFBoxResourceLoader
import com.tom_roush.pdfbox.pdmodel.PDDocument
import com.tom_roush.pdfbox.rendering.PDFRenderer
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream

/**
 * 封面提取工具类
 * 用于从不同格式的电子书文件中提取封面图片
 */
class CoverExtractor(private val context: Context) {
    
    companion object {
        private const val TAG = "CoverExtractor"
        private const val COVER_CACHE_DIR = "book_covers"
        private const val COVER_WIDTH = 300
        private const val COVER_HEIGHT = 400
    }
    
    init {
        // 初始化PDFBox
        PDFBoxResourceLoader.init(context)
    }
    
    /**
     * 提取书籍封面
     * @param filePath 电子书文件路径
     * @param format 书籍格式
     * @param bookId 书籍ID，用于缓存文件名
     * @return 封面图片文件路径，如果提取失败返回null
     */
    suspend fun extractCover(filePath: String, format: BookFormat, bookId: String): String? {
        return withContext(Dispatchers.IO) {
            try {
                val coverCacheDir = File(context.cacheDir, COVER_CACHE_DIR)
                if (!coverCacheDir.exists()) {
                    coverCacheDir.mkdirs()
                }
                
                val coverFile = File(coverCacheDir, "${bookId}.jpg")
                
                // 如果缓存文件已存在，直接返回
                if (coverFile.exists()) {
                    Log.d(TAG, "Cover cache found for book: $bookId")
                    return@withContext coverFile.absolutePath
                }
                
                val bitmap = when (format) {
                    BookFormat.EPUB -> extractEpubCover(filePath)
                    BookFormat.PDF -> extractPdfCover(filePath)
                    BookFormat.MOBI -> extractMobiCover(filePath)
                }
                
                if (bitmap != null) {
                    // 保存封面到缓存
                    saveBitmapToFile(bitmap, coverFile)
                    Log.d(TAG, "Cover extracted and cached for book: $bookId")
                    return@withContext coverFile.absolutePath
                } else {
                    Log.w(TAG, "Failed to extract cover for book: $bookId")
                    return@withContext null
                }
            } catch (e: Exception) {
                Log.e(TAG, "Error extracting cover for book: $bookId", e)
                return@withContext null
            }
        }
    }
    
    /**
     * 从EPUB文件提取封面
     */
    private fun extractEpubCover(filePath: String): Bitmap? {
        return try {
            val zipInputStream = ZipInputStream(FileInputStream(filePath))
            var entry: ZipEntry?
            val imageEntries = mutableListOf<Pair<String, ByteArray>>()
            
            // 收集所有图片文件
            while (zipInputStream.nextEntry.also { entry = it } != null) {
                val entryName = entry?.name?.lowercase() ?: continue
                
                // 查找图片文件
                if (entryName.endsWith(".jpg") || entryName.endsWith(".jpeg") || 
                    entryName.endsWith(".png") || entryName.endsWith(".gif") ||
                    entryName.endsWith(".webp") || entryName.endsWith(".bmp")) {
                    
                    val imageData = zipInputStream.readBytes()
                    imageEntries.add(entryName to imageData)
                }
            }
            zipInputStream.close()
            
            // 按优先级查找封面
            val coverPatterns = listOf(
                "cover", "front", "title", "jacket", "thumbnail"
            )
            
            // 优先查找包含封面关键词的图片
            for (pattern in coverPatterns) {
                val coverEntry = imageEntries.find { it.first.contains(pattern) }
                if (coverEntry != null) {
                    val bitmap = BitmapFactory.decodeByteArray(coverEntry.second, 0, coverEntry.second.size)
                    if (bitmap != null) {
                        Log.d(TAG, "Found EPUB cover with pattern '$pattern': ${coverEntry.first}")
                        return resizeBitmap(bitmap)
                    }
                }
            }
            
            // 如果没找到，尝试第一个图片文件
            if (imageEntries.isNotEmpty()) {
                val firstImage = imageEntries.first()
                val bitmap = BitmapFactory.decodeByteArray(firstImage.second, 0, firstImage.second.size)
                if (bitmap != null) {
                    Log.d(TAG, "Using first image as EPUB cover: ${firstImage.first}")
                    return resizeBitmap(bitmap)
                }
            }
            
            Log.w(TAG, "EPUB文件没有找到封面图片: $filePath")
            null
        } catch (e: Exception) {
            Log.e(TAG, "Error extracting EPUB cover", e)
            null
        }
    }
    
    /**
     * 从PDF文件提取封面（第一页）
     */
    private fun extractPdfCover(filePath: String): Bitmap? {
        return try {
            val document = PDDocument.load(File(filePath))
            
            if (document.numberOfPages > 0) {
                val renderer = PDFRenderer(document)
                val bitmap = renderer.renderImageWithDPI(0, 72f, com.tom_roush.pdfbox.rendering.ImageType.RGB)
                document.close()
                return resizeBitmap(bitmap)
            }
            
            document.close()
            null
        } catch (e: Exception) {
            Log.e(TAG, "Error extracting PDF cover", e)
            null
        }
    }
    
    /**
     * 从MOBI文件提取封面
     * 注意：MOBI格式比较复杂，这里提供基础实现
     */
    private fun extractMobiCover(filePath: String): Bitmap? {
        return try {
            val file = File(filePath)
            val fileBytes = file.readBytes()
            
            // MOBI文件头部信息
            if (fileBytes.size < 232) {
                Log.w(TAG, "MOBI file too small: $filePath")
                return null
            }
            
            // 查找EXTH头部（包含封面信息）
            val exthOffset = findExthHeader(fileBytes)
            if (exthOffset > 0) {
                val coverOffset = findCoverOffset(fileBytes, exthOffset)
                if (coverOffset > 0) {
                    val imageData = extractImageData(fileBytes, coverOffset)
                    if (imageData != null) {
                        val bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.size)
                        if (bitmap != null) {
                            Log.d(TAG, "Successfully extracted MOBI cover")
                            return resizeBitmap(bitmap)
                        }
                    }
                }
            }
            
            // 如果EXTH方法失败，尝试查找JPEG/PNG标识符
            val jpegOffset = findImageBySignature(fileBytes, byteArrayOf(0xFF.toByte(), 0xD8.toByte(), 0xFF.toByte()))
            if (jpegOffset > 0) {
                val imageData = extractImageFromOffset(fileBytes, jpegOffset)
                if (imageData != null) {
                    val bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.size)
                    if (bitmap != null) {
                        Log.d(TAG, "Found JPEG image in MOBI file")
                        return resizeBitmap(bitmap)
                    }
                }
            }
            
            val pngOffset = findImageBySignature(fileBytes, byteArrayOf(0x89.toByte(), 0x50, 0x4E, 0x47))
            if (pngOffset > 0) {
                val imageData = extractImageFromOffset(fileBytes, pngOffset)
                if (imageData != null) {
                    val bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.size)
                    if (bitmap != null) {
                        Log.d(TAG, "Found PNG image in MOBI file")
                        return resizeBitmap(bitmap)
                    }
                }
            }
            
            Log.w(TAG, "No cover image found in MOBI file: $filePath")
            null
        } catch (e: Exception) {
            Log.e(TAG, "Error extracting MOBI cover", e)
            null
        }
    }
    
    private fun findExthHeader(fileBytes: ByteArray): Int {
        // 查找EXTH标识符
        val exthSignature = "EXTH".toByteArray()
        for (i in 0..fileBytes.size - exthSignature.size) {
            if (fileBytes.sliceArray(i until i + exthSignature.size).contentEquals(exthSignature)) {
                return i
            }
        }
        return -1
    }
    
    private fun findCoverOffset(fileBytes: ByteArray, exthOffset: Int): Int {
        // 在EXTH头部查找封面偏移量（简化实现）
        try {
            // EXTH记录通常包含封面信息，这里做简化处理
            for (i in exthOffset until minOf(exthOffset + 1000, fileBytes.size - 4)) {
                // 查找可能的图片偏移量标识
                if (i + 4 < fileBytes.size) {
                    val value = ((fileBytes[i].toInt() and 0xFF) shl 24) or
                               ((fileBytes[i + 1].toInt() and 0xFF) shl 16) or
                               ((fileBytes[i + 2].toInt() and 0xFF) shl 8) or
                               (fileBytes[i + 3].toInt() and 0xFF)
                    
                    // 检查是否为合理的偏移量
                    if (value > 0 && value < fileBytes.size - 1000) {
                        // 检查该偏移量处是否有图片数据
                        if (value + 4 < fileBytes.size) {
                            val signature = fileBytes.sliceArray(value until value + 4)
                            if (signature[0] == 0xFF.toByte() && signature[1] == 0xD8.toByte() ||
                                signature[0] == 0x89.toByte() && signature[1] == 0x50.toByte()) {
                                return value
                            }
                        }
                    }
                }
            }
        } catch (e: Exception) {
            Log.w(TAG, "Error finding cover offset in EXTH", e)
        }
        return -1
    }
    
    private fun extractImageData(fileBytes: ByteArray, offset: Int): ByteArray? {
        try {
            if (offset >= fileBytes.size - 4) return null
            
            // 检查图片类型并提取数据
            val signature = fileBytes.sliceArray(offset until offset + 4)
            
            return when {
                signature[0] == 0xFF.toByte() && signature[1] == 0xD8.toByte() -> {
                    // JPEG图片
                    extractJpegData(fileBytes, offset)
                }
                signature[0] == 0x89.toByte() && signature[1] == 0x50.toByte() -> {
                    // PNG图片
                    extractPngData(fileBytes, offset)
                }
                else -> null
            }
        } catch (e: Exception) {
            Log.w(TAG, "Error extracting image data", e)
            return null
        }
    }
    
    private fun findImageBySignature(fileBytes: ByteArray, signature: ByteArray): Int {
        for (i in 0..fileBytes.size - signature.size) {
            if (fileBytes.sliceArray(i until i + signature.size).contentEquals(signature)) {
                return i
            }
        }
        return -1
    }
    
    private fun extractImageFromOffset(fileBytes: ByteArray, offset: Int): ByteArray? {
        return extractImageData(fileBytes, offset)
    }
    
    private fun extractJpegData(fileBytes: ByteArray, offset: Int): ByteArray? {
        try {
            // 查找JPEG结束标识符 (0xFF 0xD9)
            for (i in offset + 2 until fileBytes.size - 1) {
                if (fileBytes[i] == 0xFF.toByte() && fileBytes[i + 1] == 0xD9.toByte()) {
                    return fileBytes.sliceArray(offset until i + 2)
                }
            }
            // 如果没找到结束标识符，尝试估算大小
            val estimatedSize = minOf(100000, fileBytes.size - offset)
            return fileBytes.sliceArray(offset until offset + estimatedSize)
        } catch (e: Exception) {
            Log.w(TAG, "Error extracting JPEG data", e)
            return null
        }
    }
    
    private fun extractPngData(fileBytes: ByteArray, offset: Int): ByteArray? {
        try {
            // PNG文件结构：8字节签名 + 数据块
            // 查找IEND块来确定文件结束
            val iendSignature = "IEND".toByteArray()
            for (i in offset + 8 until fileBytes.size - iendSignature.size - 4) {
                if (fileBytes.sliceArray(i until i + iendSignature.size).contentEquals(iendSignature)) {
                    return fileBytes.sliceArray(offset until i + iendSignature.size + 4)
                }
            }
            // 如果没找到IEND，尝试估算大小
            val estimatedSize = minOf(100000, fileBytes.size - offset)
            return fileBytes.sliceArray(offset until offset + estimatedSize)
        } catch (e: Exception) {
            Log.w(TAG, "Error extracting PNG data", e)
            return null
        }
    }
    
    /**
     * 调整图片大小
     */
    private fun resizeBitmap(bitmap: Bitmap?): Bitmap? {
        if (bitmap == null) return null
        
        return try {
            Bitmap.createScaledBitmap(bitmap, COVER_WIDTH, COVER_HEIGHT, true)
        } catch (e: Exception) {
            Log.e(TAG, "Error resizing bitmap", e)
            bitmap
        }
    }
    
    /**
     * 保存Bitmap到文件
     */
    private fun saveBitmapToFile(bitmap: Bitmap, file: File) {
        try {
            FileOutputStream(file).use { out ->
                bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out)
            }
        } catch (e: IOException) {
            Log.e(TAG, "Error saving bitmap to file", e)
        }
    }
    
    /**
     * 清除封面缓存
     */
    fun clearCoverCache() {
        try {
            val coverCacheDir = File(context.cacheDir, COVER_CACHE_DIR)
            if (coverCacheDir.exists()) {
                coverCacheDir.deleteRecursively()
                Log.d(TAG, "Cover cache cleared")
            }
        } catch (e: Exception) {
            Log.e(TAG, "Error clearing cover cache", e)
        }
    }
    
    /**
     * 获取封面缓存文件路径
     */
    fun getCoverCachePath(bookId: String): String? {
        val coverCacheDir = File(context.cacheDir, COVER_CACHE_DIR)
        val coverFile = File(coverCacheDir, "${bookId}.jpg")
        return if (coverFile.exists()) coverFile.absolutePath else null
    }
}